#include <iostream>
#include <sstream>
#include "PartidaServicio.h"

using namespace std;
using namespace TP::Servicios;

#define PARTIDA_EXISTENTE   1
#define JUGADOR_JUGANDO     2
#define MUNDO_INEXISTENTE   3
#define NIVEL_INEXISTENTE   4


PartidaServicio::PartidaServicio() {
}

PartidaServicio::~PartidaServicio() {
}

void PartidaServicio::iniciar() {
    
}
    
void PartidaServicio::finalizar() {
    
}
    
void PartidaServicio::mensajeEntranteManejador (IMensajero* pMensajero, const string& pMensaje) {

    //@todo: Implementar el manejador de mensajes entrantes del servicio Mundo.
    
    try
    {
        vector<string> comando;
        this->hidratarMensaje(pMensaje, comando);
        
        if (PARTIDA == comando[0])
        {
            if (LISTAR_PARTIDAS == comando [1])
                this->__listarPartidas (pMensajero);
            
            if (UNIR_PARTIDA == comando[1])
                this->__unirAPartida(pMensajero, comando);
            
            if (CREAR_PARTIDA == comando [1])
                this->__crearPartida(pMensajero, comando);
        }
        
    }
    catch (Excepcion& pEx)
    {
        cerr << pEx.what() << endl;
    }
}

void PartidaServicio::__listarPartidas(IMensajero* pMensajero) {

    vector<string> lista = this->_motorJuego->listarPartidas();
    
    if (lista.size() > 0)
    {
        std::stringstream respuesta;
        respuesta << "";

        for (vector<string>::iterator it = lista.begin(); it != lista.end(); ++it)
            respuesta << (*it) << endl;
        
        this->notificar(pMensajero, respuesta.str());
    }
    else
        this->notificar(pMensajero, NULO);
}

void PartidaServicio::__unirAPartida (IMensajero* pMensajero, vector<string>& pComando) {
    throw Excepcion ("PartidaServicio.__unirAPartida no implementada.");
}

void PartidaServicio::__crearPartida (IMensajero* pMensajero, vector<string>& pComando) {
    
    Jugador* jugador = NULL;
    Mundo* mundo = NULL;    
    Nivel* nivel = NULL;

    try
    {
        // formato de comando: {0:Partida, 1:CrearPartida, 2:Jugador, 3:nombreMundo, 4:idNivel, 5:pNombrePartida}
        jugador = Jugador::crearDeXML(pComando[2]);
        if (NULL != this->_motorJuego->getPartidaPorJugador (jugador))
            throw JUGADOR_JUGANDO;

        if (this->partidaExistente (pComando[5]))
            throw PARTIDA_EXISTENTE;

        mundo = this->_mundoSrv->getMundoPorNombre (pComando[3]);
        
        if (NULL == mundo)
            throw MUNDO_INEXISTENTE;

        std::stringstream strstream (pComando[4]);
        unsigned int idNivel = 0;
        strstream >> idNivel;
        nivel = mundo->getNivel (idNivel);
        if (NULL == nivel)
            throw NIVEL_INEXISTENTE;
        
        this->_motorJuego->correrPartida(new Partida (pComando[5], nivel->getEscenario(), jugador));
        this->notificar (pMensajero, this->_motorJuego->getPartidaPorJugador(jugador)->aXML());
    }
    catch (int pEx)
    {
        switch (pEx)
        {
            case PARTIDA_EXISTENTE:
                this->notificarError (pMensajero, "Ya existe una partida que posee el nombre especificado.");        
                break;

            case JUGADOR_JUGANDO:
                this->notificarError (pMensajero, "El jugador se encuentra jugnado una partida actualmente.");
                break;

            case MUNDO_INEXISTENTE:
                this->notificarError (pMensajero, "El mundo especificado no existe.");
                break;

            case NIVEL_INEXISTENTE:
                this->notificarError (pMensajero, "El nivel especificado no existe.");
                break;
        }
    }
    catch (Excepcion& pEx)
    {
        cerr << pEx.what() << endl;
    }
}

bool PartidaServicio::partidaExistente(const string& pNombrePartida){
    return NULL != this->_motorJuego->getPartidaPorNombre(pNombrePartida);
}

MotorJuego* PartidaServicio::setMotorJuego (MotorJuego* pMotor){
    this->_motorJuego = pMotor;
    return pMotor;
}

MundoServicio* PartidaServicio::setMundoServicio (MundoServicio* pServicio){
    this->_mundoSrv = pServicio;
    return pServicio;
}

